package com.clementheliou.cheliou.business.technical.security.authentication.model.fest.asserter;

import static com.clementheliou.cheliou.business.technical.fest.assertions.CHeliouBusinessAssertions.assertThat;
import static org.fest.assertions.api.Assertions.assertThat;

import java.awt.Dimension;

import org.fest.assertions.api.AbstractAssert;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

import com.clementheliou.cheliou.business.technical.fest.assertions.CHeliouBusinessAssertions;
import com.clementheliou.cheliou.business.technical.security.authentication.model.AuthenticationDetails;
import com.clementheliou.cheliou.dal.model.member.Member;
import com.clementheliou.cheliou.dal.model.member.enumeration.MemberRole;

/**
 * FEST asserter used to make test code about {@link AuthenticationDetails} instances more readable.
 * It should only be used through the static factory that can be found into the project assertions
 * class ( {@link CHeliouBusinessAssertions}).
 * 
 * @author Clément HELIOU (clement.heliou@gmail.com)
 * @see {@link AbstractAssert};
 * @see {@link AuthenticationDetails};
 * @see {@link CHeliouBusinessAssertions}.
 * @since 1.0
 */
public class AuthenticationDetailsAsserter extends AbstractAssert<AuthenticationDetailsAsserter, AuthenticationDetails> {

	/**
	 * Constructor from the {@link AuthenticationDetails} to be asserted.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param actual the {@link AuthenticationDetails} instance to be asserted.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter(final AuthenticationDetails actual) {
		super(actual, AuthenticationDetailsAsserter.class);
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance has the expected first name.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param expectedFirstName the expected first name value.
	 * @return the asserter instance after this assertion.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter hasFirstName(final String expectedFirstName) {
		isNotNull();
		assertThat(actual.getFirstName()).isEqualTo(expectedFirstName);
		return this;
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance contains data related to the
	 * expected {@link Member}.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param expectedMemberData the expected {@link Member} data.
	 * @return the asserter instance after this assertion.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter hasMemberData(final Member expectedMemberData) {
		assertThat(expectedMemberData).isNotNull();
		assertThat(actual).isNotNull();
		assertThat(actual.getAuthorities()).hasSameSizeAs(expectedMemberData.getRolesList());
		assertThat(actual.getFirstName()).isEqualTo(expectedMemberData.getFirstName());
		assertThat(actual.getMemberLocale()).isEqualTo(expectedMemberData.getLocale());
		assertThat(actual.getMemberId()).isEqualTo(expectedMemberData.getId());
		assertThat(actual.getName()).isEqualTo(expectedMemberData.getName());
		assertThat(actual.getPassword()).isEqualTo(expectedMemberData.getPassword());

		SimpleGrantedAuthority currentAuthority;
		for (MemberRole role : expectedMemberData.getRolesList()) {
			currentAuthority = new SimpleGrantedAuthority(role.getCode());
			assertThat(actual.getAuthorities()).contains(currentAuthority);
		}

		return this;
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance has the expected name.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param expectedName the expected name value.
	 * @return the asserter instance after this assertion.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter hasName(final String expectedName) {
		isNotNull();
		assertThat(actual.getName()).isEqualTo(expectedName);
		return this;
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance has a null password.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the asserter instance after this assertion.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter hasNullPassword() {
		isNotNull();
		assertThat(actual.getPassword()).isNull();
		return this;
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance has a null username.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the asserter instance after this assertion.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter hasNullUsername() {
		isNotNull();
		assertThat(actual.getUsername()).isNull();
		return this;
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance has the expected screen size.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param expectedScreenSize the expected screen size as a {@link Dimension} instance.
	 * @return the asserter instance after this assertion.
	 * @see {@link Dimension}.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter hasScreenSize(final Dimension expectedScreenSize) {
		isNotNull();
		assertThat(actual.getScreenSize()).isEqualTo(expectedScreenSize);
		return this;
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance has the expected username.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @param expectedUsername the expected username value.
	 * @return the asserter instance after this assertion.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter hasUsername(final String expectedUsername) {
		isNotNull();
		assertThat(actual.getUsername()).isEqualTo(expectedUsername);
		return this;
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance account is not expired.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the asserter instance after this assertion.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter isAccountNonExpired() {
		isNotNull();
		assertThat(actual.isAccountNonExpired()).isTrue();
		return this;
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance account is not locked.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the asserter instance after this assertion.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter isAccountNonLocked() {
		isNotNull();
		assertThat(actual.isAccountNonLocked()).isTrue();
		return this;
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance credentials are not expired.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the asserter instance after this assertion.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter isCredentialsNonExpired() {
		isNotNull();
		assertThat(actual.isCredentialsNonExpired()).isTrue();
		return this;
	}

	/**
	 * Asserts that current {@link AuthenticationDetails} instance is enabled.
	 * 
	 * @author Clément HELIOU (clement.heliou@gmail.com)
	 * @return the asserter instance after this assertion.
	 * @since 1.0
	 */
	public AuthenticationDetailsAsserter isEnabled() {
		isNotNull();
		assertThat(actual.isEnabled()).isTrue();
		return this;
	}
}
